#pragma once

#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>

template <class T>
class blockQueue
{
public:
    blockQueue(int cap)
        : _cap(cap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_product_cond, nullptr);
        pthread_cond_init(&_consum_cond, nullptr);
    }

    ~blockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_product_cond);
        pthread_cond_destroy(&_consum_cond);
    }

    void enQueue(const T& in)//生产者生产
    {
        pthread_mutex_lock(&_mutex);//加锁，维护生产者与消费者之间的互斥

        if(_block_queue.size() == _cap)//队列满了，不能生产
        {
            //1. 让线程去等待  2. 释放曾经的 mutex 锁
            pthread_cond_wait(&_product_cond, &_mutex);//去等待，直到被唤醒
        }

        _block_queue.push(in);//生产

        pthread_cond_signal(&_consum_cond);//通知消费者来消费

        pthread_mutex_unlock(&_mutex);
    }

    void popQueue(T& out)//消费者消费
    {
        pthread_mutex_lock(&_mutex);//加锁，维护生产者与消费者之间的互斥

        if(_block_queue.size() == 0)//队列为空，不能消费
        {
            //1. 让线程去等待  2. 释放曾经的 mutex 锁
            pthread_cond_wait(&_consum_cond, &_mutex);//去等待，直到被唤醒
        }

        out = _block_queue.front();//消费
        _block_queue.pop();

        pthread_cond_signal(&_product_cond);//通知生产者来生产

        pthread_mutex_unlock(&_mutex);
    }

private:
    std::queue<T> _block_queue;
    int _cap;//总上限

    pthread_mutex_t _mutex;
    pthread_cond_t _product_cond;//给生产者的条件变量
    pthread_cond_t _consum_cond;//给消费者的条件变量
};